#include "AriesMath.h"

namespace Core{
const double AriesMath::E = 2.7182818284590452354;
const double AriesMath::PI = 3.14159265358979323846;

const double AriesMath::ONE_OVER_PI = 1.0 / AriesMath::PI;
const double AriesMath::PI_OVER_TWO = AriesMath::PI * 0.5;
const double AriesMath::PI_OVER_THREE = AriesMath::PI / 3.0;
const double AriesMath::PI_OVER_FOUR = AriesMath::PI / 4.0;
const double AriesMath::PI_OVER_SIX = AriesMath::PI / 6.0;
const double AriesMath::THREE_PI_OVER_TWO = (3.0 * AriesMath::PI) * 0.5;
const double AriesMath::TWO_PI = 2.0 * AriesMath::PI;
const double AriesMath::ONE_OVER_TOW_PI = 1.0 / (2.0 * AriesMath::PI);
const double AriesMath::RADIANS_PER_DEGREE = AriesMath::PI / 180.0;
const double AriesMath::DEGREES_PER_RADIAN = 180.0 /AriesMath::PI;
const double AriesMath::RADIANS_PER_ARCSECOND = AriesMath::RADIANS_PER_DEGREE / 3600.0;

const double AriesMath::EPSILON1 = 0.1;
const double AriesMath::EPSILON2 = 0.01;
const double AriesMath::EPSILON3 = 0.001;
const double AriesMath::EPSILON4 = 0.0001;
const double AriesMath::EPSILON5 = 0.00001;
const double AriesMath::EPSILON6 = 0.000001;
const double AriesMath::EPSILON7 = 0.0000001;
const double AriesMath::EPSILON8 = 0.00000001;
const double AriesMath::EPSILON9 = 0.000000001;
const double AriesMath::EPSILON10 = 0.0000000001;
const double AriesMath::EPSILON11 = 0.00000000001;
const double AriesMath::EPSILON12 = 0.000000000001;
const double AriesMath::EPSILON13 = 0.0000000000001;
const double AriesMath::EPSILON14 = 0.00000000000001;
const double AriesMath::EPSILON15 = 0.000000000000001;
const double AriesMath::EPSILON16 = 0.0000000000000001;
const double AriesMath::EPSILON17 = 0.00000000000000001;
const double AriesMath::EPSILON18 = 0.000000000000000001;
const double AriesMath::EPSILON19 = 0.0000000000000000001;
const double AriesMath::EPSILON20 = 0.00000000000000000001;


const double AriesMath::GRAVITATIONALPARAMETER = 3.986004418e14;
const double AriesMath::SOLAR_RADIUS = 6.955e8;
const double AriesMath::LUNAR_RADIUS = 1737400.0;

const double AriesMath::SIXTY_FOUR_KILOBYTES = 64 * 1024;

AriesMath::AriesMath(void)
{
}


AriesMath::~AriesMath(void)
{
}

double AriesMath::round(const double& r)
{
	return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);
}

int AriesMath::toSNorm(const double& value)
{
	return round((clamp(value, -1.0, 1.0) * 0.5 + 0.5) * 255.0);
}

double AriesMath::fromSNorm(const int& value)
{
	return clamp(value, 0.0, 255.0) / 255.0 * 2.0 - 1.0;
}

double AriesMath::sinh(const double& value)
{
	double part1 = pow(E, value);
	double part2 = pow(E, -1.0 * value);
	return (part1 - part2) * 0.5;
}

double AriesMath::cosh(const double& value)
{
	double part1 = pow(E, value);
	double part2 = pow(E, -1.0 * value);
	return (part1 + part2) * 0.5;
}

double AriesMath::lerp(const double& p, const double& q, const double& time)
{
	return ((1.0 - time)*p) + (time * q);
}

double AriesMath::toRadians(const double& degrees)
{
	return degrees * RADIANS_PER_DEGREE;
}

double AriesMath::toDegrees(const double& radians)
{
	return radians * DEGREES_PER_RADIAN;
}

double AriesMath::convertLongitudeRange(const double& angle)
{
	double twoPi = TWO_PI;
	double simplified = angle - floor(angle / twoPi) * twoPi;

	if (simplified < -PI)
		return simplified + twoPi;
	if (simplified >= PI)
		return simplified - twoPi;

	return simplified;
}

double AriesMath::negativePiToPi(double x)
{
	double epsilon10 = EPSILON10;
	double pi = PI;
	double two_pi = TWO_PI;

	while (x < -(pi + epsilon10))
	{
		x += two_pi;
	}
	if (x < -pi) {
		return -pi;
	}
	while (x > pi + epsilon10) {
		x -= two_pi;
	}
	return x > pi ? pi : x;
}

double AriesMath::zeroToTwoPi(double x)
{
	double value = fmod(x, TWO_PI);

	// We do a second modules here if we add 2Pi to ensure that we don't have any numerical issues with very
	// small negative values.
	return (value < 0.0) ? fmod((value + TWO_PI), TWO_PI) : value;
}

bool AriesMath::equalsEpsilon(const double& left, const double& right, const double& epsilon)
{
	return abs(left - right) <= epsilon;
}

int AriesMath::factorial(const int& n)
{
	int f;
	if (n == 0 || n == 1)
		f = 1;
	else
		f = factorial(n - 1)*n;

	return f;
}

double AriesMath::incrementWrap(double n, const double& maximumValue, const double& minimumValue)
{
	++n;
	if (n > maximumValue) {
		n = minimumValue;
	}
	return n;
}

bool AriesMath::isPowerOfTwo(const int& n)
{
	return (n != 0) && ((n & (n - 1)) == 0);
}

int AriesMath::nextPowerOfTwo(int n)
{
	// From http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
	--n;
	n |= n >> 1;
	n |= n >> 2;
	n |= n >> 4;
	n |= n >> 8;
	n |= n >> 16;
	++n;

	return n;
}

double AriesMath::clamp(const double& value, const double& min, const double& max)
{
	return value < min ? min : (value > max ? max : value);
}

double AriesMath::acosClamped(const double& value)
{
	return acos(clamp(value, -1.0, 1.0));
}

double AriesMath::asinClamped(const double& value)
{
	return asin(clamp(value, -1.0, 1.0));
}

}
